<template>
    <div class="pe-switch"
        :class="[(loading || loadingFlag) || (disabled || disabledFlag) ? 'is-disabled' : '', sizeArr.includes(size) ? `pe-switch-${size}` : '']"
        :style="{ cursor: (loading || loadingFlag) || (disabled || disabledFlag) ? 'not-allowed' : 'pointer' }"
        @click.stop="onClick">
        <span v-if="inactiveIcon || inactiveText" class="pe-switch-off-text"
            :style="{ color: value === inactiveValue ? 'var(--pe-switch-on-color)' : '' }">
            <template v-if="activeIcon">
                <inactiveIcon />
            </template>
            <template v-if="!inactiveIcon && inactiveText">
                {{ inactiveText }}
            </template>
        </span>
        <div class="pe-switch-main" :class="[value === activeValue ? 'is-checked' : '']" :style="{
            backgroundColor: value === activeValue ? 'var(--pe-switch-on-color)' : 'var(--pe-switch-off-color)',
            border: `2px solid var(--pe-switch-${value === activeValue ? 'on' : 'off'}-color)`
        }">
            <input ref="inputRef" class="pe-switch-input" type="checkbox" v-model="value" :true-value="activeValue"
                :false-value="inactiveValue" :disabled="disabled || disabledFlag" :name="name" :id="id"
                :tabindex="tabindex" :aria-label="ariaLabel" @change="change" @click.stop>
            <div class="pe-switch-item">
                <Loading v-if="loading || loadingFlag" class="is-loading" />
                <div
                    :style="{ color: value === activeValue ? 'var(--pe-switch-on-color)' : 'var(--pe-switch-on-color)' }">
                    <template v-if="value === activeValue">
                        <slot name="active-action"></slot>
                    </template>
                    <template v-else>
                        <slot name="inactive-action"></slot>
                    </template>
                </div>
            </div>
        </div>
        <span v-if="activeIcon || activeText" class="pe-switch-on-text"
            :style="{ color: value === activeValue ? 'var(--pe-switch-on-color)' : '' }">
            <template v-if="activeIcon">
                <activeIcon />
            </template>
            <template v-if="!activeIcon && activeText">
                {{ activeText }}
            </template>
        </span>
    </div>
</template>

<script setup lang="ts">
import { Component, nextTick, ref } from "vue"
import Loading from "../../icons/loading.vue";

const value = defineModel<boolean | string | number>({ default: false })

/**
 * @param disabled 是否禁用
 * @param loading 是否显示加载中
 * @param size switch 的大小
 * @param active-icon switch 状态为 on 时所显示图标，设置此项会忽略 active-text
 * @param inactive-icon switch 状态为 off 时所显示图标，设置此项会忽略 inactive-text
 * @param active-text switch 打开时的文字描述
 * @param inactive-text switch 的状态为 off 时的文字描述
 * @param active-value switch 状态为 on 时的值
 * @param inactive-value switch的状态为 off 时的值
 * @param name switch 对应的 name 属性
 * @param before-change switch 状态改变前的钩子， 返回 false 或者返回 Promise 且被 reject 则停止切换
 * @param id input 的 id
 * @param tabindex input 的 tabindex
 * @param aria-label 等价于原生 input aria-label 属性
 */
interface Props {
    disabled?: boolean,
    loading?: boolean,
    size?: 'small' | 'default' | 'large'
    activeIcon?: Component,
    inactiveIcon?: Component,
    activeText?: string,
    inactiveText?: string,
    activeValue?: boolean | string | number,
    inactiveValue?: boolean | string | number,
    name?: string,
    beforeChange?: boolean | Function,
    id?: string,
    tabindex?: string | number,
    ariaLabel?: string
}

const props = withDefaults(defineProps<Props>(), {
    disabled: false,
    loading: false,
    size: "default",
    activeValue: true,
    inactiveValue: false,
    beforeChange: true
})

const emits = defineEmits(["change"])

const sizeArr = ["small", "large"]

const inputRef = ref()
const loadingFlag = ref<boolean>(false)
const disabledFlag = ref<boolean>(false)
const onClick = async () => {
    let flag = true
    if (typeof props.beforeChange === 'boolean') {
        flag = props.beforeChange
    } else if (typeof props.beforeChange === 'function') {
        loadingFlag.value = true
        disabledFlag.value = true
        try {
            flag = await props.beforeChange()
        } finally {
            loadingFlag.value = false
            disabledFlag.value = false
        }
    }
    if (flag) {
        nextTick(() => {
            inputRef.value.click()
        })
    }
}

const change = (event: any) => {
    emits("change", event.target.checked ? props.activeValue : props.inactiveValue)
}
</script>

<script lang="ts">
export default {
    name: "pe-switch"
}
</script>
